Skip to content

docs(workflows): send React Email components through PostHog - #21984

Merged
Silthus merged 33 commits into
masterfrom
docs/react-email-transactional-email
Nov 13, 2026
Merged

Silthus merged 33 commits into
masterfrom
docs/react-email-transactional-email

Conversation

@Silthus

@Silthus Silthus commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Changes

A developer who writes emails with React Email has no page that shows how to send them through PostHog. From posthog-node 5.69.0, posthog.emails.send takes a React Email element as react and renders the HTML and the plain text itself. The docs don't mention react yet, and the Node.js page's React Email example still renders the HTML by hand.

This PR adds Send React Email components with PostHog under Send transactional emails, and a React Email sidebar entry after API. The page shows:

  • the install, with @react-email/render, the optional peer dependency that the SDK renders with;
  • a component built with the react-email components, and the client setup;
  • a send that passes the component as react, with the plain text that the SDK makes, and how to send your own text;
  • the two errors of a React send, missing_react_renderer and react_render_failed, and the invalid_form refusals, including sensitive on an SDK earlier than 5.71.0;
  • the Next.js limit: a React send on the edge runtime fails, so send on the Node.js runtime;
  • the alternative: render the component yourself with render and toPlainText, and send html and text.

The Node.js page's React Email example now passes react, and its field list names react and links to the new page.

Ticket: https://github.com/PostHog/michaelr-context/issues/48 (private). The base PR, #21819, merged. This branch merges master in and keeps the later changes of #22088 (tracking and sensitive) and #22032 (attachments).

This update continues the first version of this PR, from 2026-11-05, on the same branch, with its commits and authorship kept.

Impact

Pays into the Workflows goal: a code send is a billed Workflows email. A React send reaches PostHog as the same request as any other code send, so no metric counts the sends that this page causes. The map's metric, code sends by integration, counts the framework adapters, not this page.

Note

🔵 Merge risk: low · two-way door

  • Docs readers in both regions see one more sidebar entry under Send transactional emails. Cosmetic. The screenshots below cover it.
  • React Email developers get a new page. Its code runs as written: a script builds an app from the page's own install line and code blocks, and sends through posthog-node 5.71.0 with only fetch stubbed. Each error in its table and its Next.js edge claim ran against the real SDK.
  • Readers of the Node.js page who copy its React Email example get a react send in place of a render call. That snippet is a fragment, and no script runs it. Its residual risk is cosmetic: a copy that fails shows its error at once.
  • Switch-off: none: live on deploy, fix forward with a docs edit.
  • Tier: non-critical

Sidebar seam. src/navs/index.js is a shared file. Three other docs PRs add one entry each under the same parent: Nodemailer (#21987) after Node.js, and Rails (#21986) and Better Auth after API. This PR adds one entry after API and reorders nothing. The PR that merges second resolves a one-line conflict.

Sidebar before and after

The sidebar gets one entry, React Email, after API. The 640 px rows open the docs navigation.

Before (posthog.com) After (preview of b68a98a)
Light, 1440 px Before: Node.js page, light, 1440 px After: Node.js page, light, 1440 px
Dark, 1440 px Before: Node.js page, dark, 1440 px After: Node.js page, dark, 1440 px
Light, 640 px, navigation open Before: navigation, light, 640 px After: navigation, light, 640 px
Dark, 640 px, navigation open Before: navigation, dark, 640 px After: navigation, dark, 640 px

Node.js page, Send content from your code

Before After
Light, 1440 px Before: render section, light, 1440 px After: react section, light, 1440 px
Dark, 640 px Before: render section, dark, 640 px After: react section, dark, 640 px

New page

Light Dark
1440 px React Email page, light, 1440 px React Email page, dark, 1440 px
640 px React Email page, light, 640 px React Email page, dark, 640 px
Send an email, 640 px Send section, light, 640 px Send section, dark, 640 px
Errors, 1440 px Errors table, light, 1440 px Errors table, dark, 1440 px
Next.js and self-render, 1440 px Next.js section, light, 1440 px Render it yourself section, dark, 1440 px

Evidence

  • Owed proofs: ui-walk (the screenshots above, from the preview of b68a98a) and live-run (gap: the map sends one live email from each branch at its head SHA before release, in one session. This PR runs no live send of its own).
  • CI on b68a98a: every check passes: the preview build, Vale, markdownlint, Spelling, broken links, Docs .md redirects, Semgrep, CodeQL, and Wiz.
  • Console: the preview pages log no error that posthog.com doesn't log on the same page, except one 404 for the page's .md copy. The preview serves no .md copy for any page, including unchanged ones, such as /docs/feature-flags.md.
  • Local checks: Prettier 2.8.8 passes on src/navs/index.js. pnpm format doesn't cover .mdx files.
  • The page's code runs at b68a98a. A script reads the page, installs exactly its npm install line with pnpm, writes each code block to the file that its first-line comment names, and runs both sends against a stubbed fetch with the real posthog-node 5.71.0, @react-email/render 2.3.1, and react-email 6.11.12. Each send makes one POST to /api/projects/@current/messaging/send/email/ with template_key, subject, to, distinct_id, the secret key, and the Idempotency-Key header. The react send passes the element and no html. The SDK renders the HTML, and the text is toPlainText of the HTML, with the button's link. No react field goes on the wire. The self-rendered send produces the same HTML and text.
  • Red first. The same script on the page at 6c924a7, before this change, fails: that page has no react send and no self-rendered send to run.
  • Errors table. A second script sends through the real SDK: a component that throws, and one that never finishes, return react_render_failed with the cause. react with html, and react with templateId, return invalid_form. On posthog-node 5.70.0, sensitive returns invalid_form; on 5.71.0 it goes on the wire. A send with your own text sends that text and the rendered HTML. In an app without @react-email/render, a react send returns missing_react_renderer. None of these sends a request.
  • Next.js edge. A Next.js 16.4.6 app sends the same component from a Node.js route handler and from an edge route handler. The Node.js route sends in milliseconds. The edge route returns react_render_failed after the 15-second request timeout and sends nothing.
  • Test seam: the page's own code blocks, run through the real SDK, with only the HTTP call stubbed. The raw output is in the private proof store.

Decisions

Question Answer Who Where
Which inbox gets the live send? Michael's own work inbox, one for every adapter stack 👤 Human ticket
Who runs the live send? One session for the whole map, from each branch at its head SHA, not each PR 👤 Human ticket
Mark ready? Yes, once the Ready gate passes; merging still needs Michael's word 👤 Human map
Add a sidebar entry, though the repo asks to check nav changes first? Yes, one entry, as a content PR may; reviewers see it in the screenshots above 👍 Accepted default ticket
Teach react or an explicit render first? react first, replacing the explicit render as the main send; the explicit render stays as the alternative 🤖 Agent ticket
Install @react-email/render by name? Yes: it's the SDK's optional peer, and the SDK's own error fix says to install it 🤖 Agent ticket
Say that React Email fails on the edge, or only the SDK's render? React Email: a route that renders it itself on the edge also crashed, so the page doesn't offer self-rendering as the edge fix 🤖 Agent ticket
Where does the entry go? After API, the same place as before this update 🤖 Agent ticket

Involvement: no grilling round for this PR; reviews: the first version had GPT-6.1 Sol (round 1 and a final read) and ReviewHog (two rounds). This update had a cross-model panel of seven lenses (Claude Opus 5.5 and GPT-6.1 Sol), a narrow round 2 on the fixes, and a final read; proof captured.

Checklist

  • I've read the docs and/or content style guides.
  • Words are spelled using American English
  • Use relative URLs for internal links
  • I've checked the pages added or changed in the preview build
  • If I moved a page, I added a redirect in vercel.json (no page moved)

🤖 Generated with Claude Code

mayteio and others added 28 commits October 24, 2026 10:38
Document how to make a Workflows email template transactional and send it with POST /api/projects/:project_id/messaging_templates/:template_id/send/. The page covers the API key, the request and response, idempotency keys, error codes, rate limits, and how transactional emails behave. The page is marked beta.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: a0274fa0-d9be-48bf-b601-f153decf241d
…e SDKs

- Send through `POST /messaging/send/email/` with `template.id`. The template route still works.
- Read an email's status with `GET /messaging/emails/:message_id/`: statuses, reasons, 404 cases, scopes and read limits.
- Send and read with the Python and Node.js SDKs.
- Add `recipient_unreachable` to the errors table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
- The Node.js example turns off local evaluation, and both examples keep the SDK's error.
- The status examples handle the error first and explain retrying a not_found.
- The SDK section adds install, client reuse, timeouts and retries, uncertain outcomes, and a no-network testing example.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
…m pages

The overview keeps the template, key, idempotency, errors, statuses and behavior. Node.js, Python and API pages hold the setup, send, status, retries and testing for each platform, with a sidebar group like push notifications.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
…he overview

- A quick start links to the Node.js, Python and API pages.
- Creating an email follows the Transactional section's wizard, and the hidden workflow explanation is gone.
- Agents can set it up with the PostHog MCP server.
- Protect sensitive data turns off click tracking and keeps deliveries, opens and statuses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
The send endpoint now takes a flat body (PostHog/posthog#126287), so the field table, the curl example and the engagement events note use template_id and distinct_id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
…il API page

Document the code form of the send route (template_key with the subject
and body), capture_engagement, the checks that only apply to it, and a
delivery_unavailable anchor for the 503's docs link.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mits

Add DKIM-Signature and Received to the reserved headers, the header name
and value limits, the tag length, and that reply_to takes bare addresses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…only

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t template_key and ph_ tags do

- A retry with the same Idempotency-Key is the same request when every field of the code-form table matches.
- template_key groups the email's metrics and sends.
- A tag name that starts with ph_, in any case, is refused.
- capture_engagement on a template send defaults to the project's setting.
- Drop a double blank line after the checks table (fix-mdx).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ell out the ph_ case rule

- The template-send table gets a capture_engagement row with the project default, and says a retry sends the field the same way.
- The code-form row keeps only its own default.
- A ph_ tag name is refused in uppercase or lowercase.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

# Conflicts:
#	contents/docs/workflows/transactional-emails/api.mdx
#	contents/docs/workflows/transactional-emails/node.mdx
#	contents/docs/workflows/transactional-emails/python.mdx
…code send

The first release sends content from code with template_key, subject, html and text only. React Email output is rendered by the app and sent as html.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Drop capture_engagement from the template send: the send route
  refuses it there, with the other fields of content from your code.
- Fold sender_not_allowed into sender_not_verified, the code the
  first release returns for a from address no verified sender can use.
- Add "Send content from your code" to the Node.js and Python pages,
  with a React Email example rendered by the app.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… in a replay

- A field error is a 400 with type validation_error, a field code
  such as required or invalid, and attr naming the field.
- A replay also compares the sender PostHog chose, so a retry without
  from after the default sender changed returns idempotency_key_reused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ntify distinct ID

Add "Link emails to your users" to the API, Node.js and Python pages: pass
the distinct ID you pass to identify(), what happens without one today (a
separate person keyed by the email address), and that invites and signup
checks can leave it out. The overview and the API tables point there
instead of "always send it".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Node.js and Python client examples used <ph_project_api_key> and a
hard-coded ingestion host, which the site doesn't replace. They now use
<ph_project_token> and <ph_client_api_host>, as the SDK pages do, so a
logged-in reader sees their own project token and host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…atus reads

A send needs transactional_email:write and a status read needs
transactional_email:read or :write. Keys with a hog_flow scope still work.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The key steps still picked Workflow, which creates a hog_flow key. The
scopes list names the new scope Transactional email.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… email scope

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A status read right after a send can answer 404 for a few seconds,
until the send's first status arrives. Say so where the API page
lists the 404, and that a retry after a short wait is the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
posthog-python#1171 ships as a minor bump, and PyPI is already at
7.83.2, so the code send arrives in 7.84.0, not 7.83.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A React Email developer keeps React Email to write emails, renders each
component in the app with render and toPlainText from react-email, and
sends the HTML and the text with the Node.js SDK. The page sits under
Send transactional emails, and the Node.js page links to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the docs Improvements or additions to product documentation, "Docs" label Nov 5, 2026
@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Deploy preview

Status Details Updated (UTC)
🟢 Ready View preview Nov 13, 2026 05:46AM

Changed pages

Page Source
Send transactional emails contents/docs/workflows/transactional-emails/index.mdx
Send transactional emails with Node.js contents/docs/workflows/transactional-emails/node.mdx
Send React Email components with PostHog contents/docs/workflows/transactional-emails/react-email.mdx

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed 6fab67b: 2 Should fix.

See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed 6c924a7: no findings.

@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Bundle report

Total JS (gzip)

12.06 MiB (-5.9 KiB / -0.0%)

Largest changed named chunks
Chunk Gzip Δ vs master
96d7471d5e9a16acef8c26a631516069d2d2075e.js 58.8 KiB new
55fe8f110ecad002fac9ec7d72d452eabea053fc.js 16.3 KiB new
580a52ecc2b5c3a295768f63c6463d62b2b166db.js 7.0 KiB new
96de664570b44467a6d0591760da6319c7a1ad80.js 126.5 KiB +1.9 KiB / +1.5%
d68185948132f79a6e51eabe8146722818e25fa9.js 1.1 KiB new

Eager graph (modules shipped in each entrypoint's initial chunks)

Entrypoint Eager size Budget Modules
✅ app 10.40 MiB (-0.2 KiB / -0.0%) report-only 1099
Largest modules in the app closure
Module Size
css ./node_modules/.pnpm/css-loader@5.2.7_webpack@5.101.3/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[8].oneOf[1].use[1]!./node_modules/.pnpm/postcss-loader@4.3.0_postcss@8.5.6_webpack@5.101.3/node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[8].oneOf[1].use[2]!./src/styles/global.css 1022.3 KiB
./src/components/Stickers/Stickers.tsx 696.4 KiB
./node_modules/.pnpm/@posthog+icons@0.36.6_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js 354.8 KiB
./node_modules/.pnpm/react-markdown@8.0.7_@types+react@16.14.66_react@18.3.1/node_modules/react-markdown/lib/react-markdown.js + 88 modules 351.4 KiB
./node_modules/.pnpm/framer-motion@14.0.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/framer-motion/dist/es/render/components/motion/proxy.mjs + 126 modules 287.2 KiB
./node_modules/.pnpm/cloudinary-core@2.14.0_lodash@4.17.21/node_modules/cloudinary-core/cloudinary-core.js 281.9 KiB
./src/components/SearchUI/index.tsx + 87 modules 273.1 KiB
./gatsby-browser.tsx + 59 modules 258.5 KiB
./node_modules/.pnpm/@posthog+brand@0.13.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/construction-1.mjs 248.5 KiB
./src/components/Pricing/PricingSlider/Slider.tsx + 87 modules 240.2 KiB
./node_modules/.pnpm/@posthog+brand@0.13.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/construction-2.mjs 228.2 KiB
./node_modules/.pnpm/@posthog+brand@0.13.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/magnifying-glass.mjs 221.7 KiB
./src/hooks/useProducts.tsx + 24 modules 155.6 KiB
./src/hooks/useProduct.ts + 9 modules 149.4 KiB
./src/components/Icons/Icons.tsx 147.4 KiB

Eager-graph budgets are report-only until a baseline is established. Sizes are gzip of public/**/*.js; eager size is webpack module source bytes for the modules actually shipped in the entrypoint's initial chunks (post-tree-shake).

Base automatically changed from docs/transactional-email-api-code-form to master November 6, 2026 07:40
Silthus and others added 2 commits November 13, 2026 04:43
Take master's transactional email pages, which now hold the squashed base
of this PR and the later tracking, sensitive and attachment changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
posthog-node 5.69.0 renders a React Email element passed as react, and
makes the plain text from it. Teach that first, list its two error codes
and the edge runtime limit, and keep the explicit render as the
alternative. The Node.js page's React Email example now passes react too.

Refs PostHog/michaelr-context#48

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Vale prose linter → found 38 errors, 2 warnings, 0 suggestions in your markdown

Full report → Copy the linter results into an LLM to batch-fix issues.

Linter being weird? Update the rules!

contents/docs/workflows/transactional-emails/index.mdx — 27 errors, 0 warnings, 0 suggestions
Line Severity Message Rule
113:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
114:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
115:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
116:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
133:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
134:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
135:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
158:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
159:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
160:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
161:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
162:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
188:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
189:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
190:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
191:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
255:42 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
256:74 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
257:42 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
258:39 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
259:35 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
283:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
284:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
285:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
286:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
287:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
288:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
contents/docs/workflows/transactional-emails/node.mdx — 11 errors, 2 warnings, 0 suggestions
Line Severity Message Rule
12:127 warning Avoid trivializing words. 'easy to' can sound dismissive to the reader. PostHogDocs.Trivializers
54:72 warning Capitalize 'Feature Flags' for PostHog's product. Use 'feature flags' for the general industry concept. PostHogBase.ProductNames
146:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
147:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
175:20 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
176:14 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
178:13 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
179:18 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
180:17 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
181:26 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
198:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
199:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
200:1 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash

Silthus and others added 2 commits November 13, 2026 05:03
List invalid_form in the React send's error table, name the timeout
setting and what error.cause holds, say that sensitive needs 5.71.0,
narrow the edge limit to Next.js edge routes, where the self-rendered
path fails too, and link the overview's React Email mention to the page.

Refs PostHog/michaelr-context#48

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… Email guide

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed b68a98a: no findings.

@Silthus

Silthus commented Nov 13, 2026

Copy link
Copy Markdown
Contributor Author

@PostHog review

@posthog

posthog Bot commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

@Silthus PostHog Review is reviewing this pull request.

@Silthus
Silthus marked this pull request as ready for review November 13, 2026 06:08
@Silthus

Silthus commented Nov 13, 2026

Copy link
Copy Markdown
Contributor Author

Still owed after merge

  • The launch train sends one real email from this guide at b68a98a, with the script in the ticket's proof folder. The script reads the page by commit SHA, so the merge doesn't change it.
  • After the deploy: check that /docs/workflows/transactional-emails/react-email and the React Email sidebar entry are live on posthog.com.
  • Sidebar seam: the Nodemailer, Rails, and Better Auth docs PRs each add one entry under the same parent. The PR that merges after this one resolves a one-line conflict in src/navs/index.js and reorders nothing.
  • Overview seam: docs(workflows): Document tracking and sensitive fields for code sends #22244 reformats the overview row that now links to this page. The PR that merges second keeps the link.
  • The React Email fork PR goes upstream on release day, after this page is live, because it links here.

@Silthus
Silthus merged commit 8198ff3 into master Nov 13, 2026
27 checks passed
@Silthus
Silthus deleted the docs/react-email-transactional-email branch November 13, 2026 07:00
Silthus added a commit that referenced this pull request Nov 13, 2026
#22088 merged and #22084 closed, so no open PR rewrites the
capture_engagement, from, and engagement bullets any more. Change their
hyphens to en dashes, and the hyphens in the new bullets that #22088
and #21984 added. The "Copies and attachments" list in api.mdx stays
as it is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Silthus added a commit that referenced this pull request Nov 13, 2026
* docs(workflows): use en dashes in the transactional email docs

Replace the hyphen that separates a term from its description with
an en dash, as the style guide and Vale's EnDash rule require. Change
"rules that are easy to get wrong" to "rules that agents often get wrong".

Leave the "Copies and attachments" list in api.mdx and the
capture_engagement and engagement bullets alone: other open PRs
rewrite those lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(workflows): use en dashes on the lines that are now free

#22088 merged and #22084 closed, so no open PR rewrites the
capture_engagement, from, and engagement bullets any more. Change their
hyphens to en dashes, and the hyphens in the new bullets that #22088
and #21984 added. The "Copies and attachments" list in api.mdx stays
as it is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(workflows): use en dashes on the bullets that Vale misses

Vale's EnDash rule needs a letter before " - ", so it misses a bullet
whose term ends in bold or code, such as "**API** - Copy" and
"**`text`** - If". The review panel found 9 of them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Improvements or additions to product documentation, "Docs"

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants